﻿using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using K9Nano.Application.Features;
using K9Nano.Caching;
using K9Nano.Dependency;
using K9Nano.Domain;
using K9Nano.Share;
using K9Nano.Share.Extensions;
using Microsoft.Extensions.Logging;

namespace K9Nano.Application.Editions
{
    public class EditionManager : K9DomainServiceBase, IDomainService, IScopedDependency
    {
        private readonly IFeatureValueStore _featureValueStore;

        public IQueryable<Edition> Editions => EditionRepository.Query();
        
        public IFeatureManager FeatureManager { get; }

        protected IRepository<Edition, int> EditionRepository { get; }

        public EditionManager(IUnitOfWork uow, ILoggerFactory loggerFactory, IFeatureValueStore featureValueStore, IFeatureManager featureManager) : base(uow, loggerFactory)
        {
            _featureValueStore = featureValueStore;
            FeatureManager = featureManager;
            EditionRepository = Uow.Repository<Edition, int>();
        }
        
        public virtual Task<string> GetFeatureValueOrNullAsync(int editionId, string featureName, CancellationToken cancellation = default)
        {
            return _featureValueStore.GetEditionValueOrNullAsync(editionId, featureName, cancellation);
        }

        public virtual Task SetFeatureValueAsync(int editionId, string featureName, string value, CancellationToken cancellation = default)
        {
            return _featureValueStore.SetEditionFeatureValueAsync(editionId, featureName, value, cancellation);
        }

        public virtual async Task<IReadOnlyList<NameValue>> GetFeatureValuesAsync(int editionId)
        {
            var values = new List<NameValue>();

            foreach (var feature in FeatureManager.GetAll())
            {
                values.Add(new NameValue(feature.Name, await GetFeatureValueOrNullAsync(editionId, feature.Name) ?? feature.DefaultValue));
            }

            return values;
        }

        public virtual async Task SetFeatureValuesAsync(int editionId, params NameValue[] values)
        {
            if (values.IsNullOrEmpty())
            {
                return;
            }

            foreach (var value in values)
            {
                await SetFeatureValueAsync(editionId, value.Name, value.Value);
            }
        }

        public virtual ValueTask<Edition> CreateAsync(Edition edition, CancellationToken cancellation = default)
        {
            return EditionRepository.InsertAsync(edition, cancellation);
        }

        public virtual ValueTask<Edition> FindByNameAsync(string name, CancellationToken cancellation = default)
        {
            return EditionRepository.FirstOrDefaultAsync(edition => edition.Name == name, cancellation);
        }

        public virtual ValueTask<Edition> FindByIdAsync(int id, CancellationToken cancellation = default)
        {
            return EditionRepository.FirstOrDefaultAsync(id, cancellation);
        }

        public virtual ValueTask<Edition> GetByIdAsync(int id, CancellationToken cancellation = default)
        {
            return EditionRepository.GetAsync(id, cancellation);
        }

        public virtual ValueTask DeleteAsync(Edition edition, CancellationToken cancellation = default)
        {
            return EditionRepository.DeleteAsync(edition, cancellation: cancellation);
        }
    }
}
